﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ChatServer
{
    public partial class ChatServer : Form
    {
        List<Socket> clientProxSocketList = new List<Socket>();
        Socket ServerSocket = null;
        public ChatServer()
        {
            InitializeComponent();
        }

        private void ChatServer_Load(object sender, EventArgs e)
        {
            string HostName = Dns.GetHostName();
            IPHostEntry IpEntity = Dns.GetHostEntry(HostName);
            for (int i = 0; i < IpEntity.AddressList.Length; i++)
            {
                //从IP地址列表中筛选出IPv4类型的IP地址
                //AddressFamily.InterNetwork表示此IP为IPv4,
                //AddressFamily.InterNetworkV6表示此地址为IPv6类型
                if (IpEntity.AddressList[i].AddressFamily==AddressFamily.InterNetwork)
                {
                    this.txtIP.Text = IpEntity.AddressList[i].ToString();
                }
            }
        }
        private void btnStart_Click(object sender, EventArgs e)
        {
            if (ServerSocket == null)
            {
                //创建socket对象
                ServerSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //绑定ip和端口
                ServerSocket.Bind(new IPEndPoint(IPAddress.Parse(txtIP.Text), int.Parse(txtPoint.Text)));
                //开启侦听
                ServerSocket.Listen(10);

                //开启新的线程接收客户端的连接
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.AcceptClientConnect), ServerSocket);
            }
            else
            {
                AppendStringToLog(string.Format("当前服务端{0}:{1}已启动,请勿重复启动...", txtIP.Text, txtPoint.Text));
            }
        }

        //接收客户端的连接
        private void AcceptClientConnect(object socket)
        {
            this.AppendStringToLog("开始接收客户端的连接...");
            var serverSocket = socket as Socket;
            while (true)
            {
                var proxSocket = serverSocket.Accept();
                this.AppendStringToLog(string.Format("客户端{0}连接上了", proxSocket.RemoteEndPoint.ToString()));
                clientProxSocketList.Add(proxSocket);
                //将接收客户端消息的方法放到线程池中
                ThreadPool.QueueUserWorkItem(new WaitCallback(this.ReceiveData), proxSocket);
            }
        }

        //接收客户端的消息
        private void ReceiveData(object socket)
        {
            var proxSocket = socket as Socket;
            byte[] data = new byte[1024 * 1024];
            while (true)
            {
                int len = 0;
                try
                {

                    len = proxSocket.Receive(data, 0, data.Length, SocketFlags.None);
                }
                catch (Exception)
                {

                    //客户端非正常退出
                    AppendStringToLog(string.Format("客户端:{0}非正常退出",
                    proxSocket.RemoteEndPoint.ToString()));

                    clientProxSocketList.Remove(proxSocket);
                    StopConnect(proxSocket);
                    return;//让方法结束 终结当前接受客户端数据的异步线程
                }

                if (len <= 0)
                {
                    //客户端正常退出
                    AppendStringToLog(string.Format("客户端:{0}正常退出...",
                    proxSocket.RemoteEndPoint.ToString()));

                    clientProxSocketList.Remove(proxSocket);
                    StopConnect(proxSocket);
                    return;//让方法结束 终结当前接受客户端数据的异步线程。
                }
                string str = Encoding.Default.GetString(data, 0, len);
                //将接收到的消息放到指定文本框
                AppendStringToLog(string.Format("接收到客户端:{0}的消息是:{1}",
                    proxSocket.RemoteEndPoint.ToString(), str));
            }
        }

        //将指定字符追加到txtLog
        private void AppendStringToLog(string str)
        {
            if (txtLog.InvokeRequired)
            {
                //同步方法(不会创建新的线程执行)
                //txtLog.Invoke(new Action<string>(s =>
                //{
                //    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                //}),str);

                txtLog.BeginInvoke(new Action<string>(s =>
                {
                    this.txtLog.Text = string.Format("{0}\r\n{1}", s, txtLog.Text);
                }), str);

            }
            else
            {
                this.txtLog.Text = string.Format("{0}\r\n{1}", str, txtLog.Text);
            }

        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (clientProxSocketList.Count == 0)
                AppendStringToLog("当前没有正在连接的客户端...请等待客户端的连接...");
            else
            {
                foreach (var proxSocket in clientProxSocketList)
                {
                    if (proxSocket.Connected)
                    {
                        byte[] data = Encoding.Default.GetBytes(txtMsg.Text);
                        byte[] result = new byte[data.Length + 1];
                        result[0] = 0;
                        Buffer.BlockCopy(data, 0, result, 1, data.Length);
                        proxSocket.Send(result, 0, result.Length, SocketFlags.None);
                    }

                }
            }

        }

        private void StopConnect(Socket proxSocket)
        {
            try
            {
                if (proxSocket.Connected)
                {
                    ServerSocket = null;
                    proxSocket.Shutdown(SocketShutdown.Both);
                    proxSocket.Close(100);
                }
            }
            catch (Exception)
            {
                Thread.CurrentThread.Abort();
            }
        }

        //发送震动
        private void btnSendShake_Click(object sender, EventArgs e)
        {
            if (clientProxSocketList.Count == 0)
            {
                AppendStringToLog("当前没有正在连接的客户端...请等待客户端的连接...");
                return;
            }
            foreach (var proxSocket in clientProxSocketList)
            {
                proxSocket.Send(new byte[1] { 1 }, 0, 1, SocketFlags.None);
                return;
            }
        }

        //发送文件
        private void btnSendFile_Click(object sender, EventArgs e)
        {
            using (OpenFileDialog ofd = new OpenFileDialog())
            {
                if (ofd.ShowDialog() != DialogResult.OK)
                {
                    return;
                }
                using (FileStream file = new FileStream(ofd.FileName, FileMode.Open, FileAccess.Read))
                {
                    byte[] data = new byte[1024 * 1024];
                    int len = 1;
                    byte[] result = new byte[data.Length + 1];
                    foreach (var clienSocket in clientProxSocketList)
                    {
                        while ((len = file.Read(data, 0, data.Length)) != 0)
                        {
                            result[0] = 2;
                            Buffer.BlockCopy(data, 0, result, 1, len);
                            clienSocket.Send(result, 0, len + 1, SocketFlags.None);
                        }
                    }

                }
            }
        }

        private void btnSendThickness_Click(object sender, EventArgs e)
        {
            if (clientProxSocketList.Count == 0)
                AppendStringToLog("当前没有正在连接的客户端...请等待客户端的连接...");
            else
            {
                string Flag = txtMsgFlag.Text;
                string Content = txtMsgContent.Text;
                byte[] msgID;
                short realContent;
                if (!(Flag.Length == 6 || Flag.Length == 4))
                {
                    MessageBox.Show("报文表示长度必须为(4 OR 6)", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    return;
                }
                bool f = short.TryParse(Content, out realContent);
                if (!f)
                {
                    MessageBox.Show("报文范围为-32768~32767", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                    return;
                }
                foreach (var proxSocket in clientProxSocketList)
                {
                    if (proxSocket.Connected)
                    {
                        byte[] Msg = new byte[10];
                        byte[] msgLength = BitConverter.GetBytes((short)32767);
                        if (strToToHexByte(Flag) != null)
                        {
                            msgID = strToToHexByte(Flag);
                        }
                        else
                        {
                            MessageBox.Show("报文标识不规范!", "错误", MessageBoxButtons.OK, MessageBoxIcon.Hand);
                            return;
                        }
                        byte[] msgSeq = BitConverter.GetBytes((short)32767);
                        byte[] flag = BitConverter.GetBytes((short)32767);
                        byte[] msgReal = BitConverter.GetBytes(realContent);
                        Array.Copy(msgLength, 0, Msg, 0, 2);
                        Array.Copy(msgID, 0, Msg, 2, 2);
                        Array.Copy(msgSeq, 0, Msg, 4, 2);
                        Array.Copy(flag, 0, Msg, 6, 2);
                        Array.Copy(msgReal, 0, Msg, 8, 2);
                        proxSocket.Send(Msg, 0, Msg.Length, SocketFlags.None);
                    }

                }
            }
        }

        /// <summary>
        /// 字符串转16进制字节数组
        /// </summary>
        /// <param name="hexString"></param>
        /// <returns></returns>
        private static byte[] strToToHexByte(string hexString)
        {
            if (hexString.Substring(0, 2).ToLower() == "0x")
            {
                hexString = hexString.Substring(2);
            }
            byte[] returnBytes = new byte[hexString.Length / 2];
            for (int i = 0; i < returnBytes.Length; i++)
                try
                {
                    returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2), 16);
                }
                catch (Exception ex)
                {
                    return null; ;
                }
            return returnBytes;
        }

    }
}